<?php
if(!defined('inside')) die('You do not have permission to execute this file directly.');

spl_autoload_register('akaikiwi_autoload');
function akaikiwi_autoload($class_name) {
	//$class_name = str_replace('_', '/', $class_name);

	$paths = array(
		'akaikiwi/libs/sys',
		'akaikiwi/libs',
		'akaikiwi/libs/vendor',
		'app/libs',
		'app/controllers',
		'app/models',
		'akaikiwi',
	);

	foreach($paths as $prefix) {
		$path = $prefix . '/' . $class_name . '.php';
		if(file_exists($path)) {
			require_once $path;
			return;
		}
	}
}

// Custom error handling
set_error_handler('akaikiwi_error');
function akaikiwi_error($errno, $errstr, $errfile, $errline, $errcontext) {
	$context = var_export($errcontext, true);
	$tpl = file_get_contents('akaikiwi/views/error.php');
	$title = NULL;

	switch($errno) {
		case E_USER_ERROR:
			$title = 'ERROR';
			break;
		case E_USER_WARNING:
			$title = 'WARNING';
			break;
		case E_USER_NOTICE:
			$title = 'NOTICE';
			break;
		default:
			$title = 'UNKNOWN';
			break;
	}

	$description = $errstr;

	$config = AkaiKiwi::loadLib('Config');
	$info = $config->get_item('debugMode') ? 'File:<br />'.$errfile.' in line '.$errline.'<br /><br />Context:<br /><pre>'.$context.'</pre>' : 'None';

	$tpl = str_replace('{title}', $title, $tpl);
	$tpl = str_replace('{description}', $description, $tpl);
	$tpl = str_replace('{info}', $info, $tpl);

	echo $tpl;

	return TRUE;
}

/**
* Akaikiwi class file. This is where magic happens.
*
* @author Federico Ramirez <fedekiller@gmail.com>
* @link http://code.google.com/p/akaikiwi/
* @copyright Copyright &copy; 2008-2011 Federico Ramirez
* @license http://www.opensource.org/licenses/mit-license.php MIT Licence
*/
class AkaiKiwi {

	private static $instance;
	private static $loader;

	/**
	 * This function is called every time a page is loaded, it initiates the application.
	 */
	public function initApp() {
		// Init loader
		self::$loader = new Loader();

		// All "non-public" libraries
		self::$loader->addLib('Security');
		self::$loader->addLib('Database');
		self::$loader->addLib('Routes');
		self::$loader->addLib('Profiler');
		self::$loader->addLib('Cache');
		// Public libraries
		self::$loader->addLib('Config');
		self::$loader->addLib('UnitTesting');
		self::$loader->addLib('Pagination', FALSE);
		self::$loader->addLib('Encrypt');
		self::$loader->addLib('Session');
		self::$loader->addLib('Email', FALSE);
		self::$loader->addLib('Benchmark');
		self::$loader->addLib('Date', FALSE);
		self::$loader->addLib('Language');
		self::$loader->addLib('Image', FALSE);
		self::$loader->addLib('Auth');

		// Event
		$this->runEvent('init');

		$config = self::loadLib('Config');
		
		if($config->get_item('gzip') > 0) {
			ini_set('zlib.output_compression_level', $config->get_item('gzip'));
			ob_start("ob_gzhandler");
		} else {
			ob_start();
		}
		session_start();

		// Cache
		$cache = self::loadLib('Cache');
		$cache->init();
		
		// For profiler
		$benchmark = self::loadLib('Benchmark');
		$benchmark->add_mark('app_init');

		// Add all non-custom helpers
		self::$loader->addHelper('formhelper');
		self::$loader->addHelper('urlhelper');
		self::$loader->addHelper('ajaxhelper');

		// Init all needed libraries classes
		// So we can use models
		self::loadLib('Database');

		$security = self::loadLib('Security');
		$security->cleanRequests();

		// Autoload helpers
		foreach($config->get_item('helperAutoload') as $lib) {
			self::loadHelper($lib);
		}

		// Run routes
		$routes = self::loadLib('Routes');
		$routes->router();
		$this->baseRouter();

		// Before running the controller, I'll make sure the encoding will be UTF-8
		header('Content-Type: text/html; charset=UTF-8');

		$controllerClass = ucfirst($_GET['controller']);
		if(class_exists($controllerClass)) {
			// Event
			$this->runEvent('before_controller');
			$controller = new $controllerClass;
			if(method_exists($controller, $_GET['action'])) {
				// Event
				$this->runEvent('before_action');
				$controller->{$_GET['action']}();
				// Event
				$this->runEvent('after_action');
			} else {
				trigger_error('Action "' . $_GET['action'] . '" could not be found.');
			}
			// Event
			$this->runEvent('after_controller');
		} else {
			trigger_error('Controller "' . ucfirst($_GET['controller']) . '" could not be found.');
		}

		if($config->get_item('enableProfiler')) {
			$benchmark->add_mark('app_end');
			$profiler = self::loadLib('Profiler');
			echo $profiler->get();
		}

		// Page was loaded, save it to the cache
		$cache->write();

		// Clear and show buffer
		ob_end_flush();
	}

	/**
	 * This function will run all hooks with the given event
	 */
	private function runEvent($name) {
		$config = AkaiKiwi::loadLib('Config');
		foreach($config->get_item('hooks') as $hook) {
			if($hook['event'] == $name) {
				require_once $hook['path']. '/' . $hook['class'] . '.php';
				$h = new $hook['class'];
				$h->{$hook['method']}($hook['args']);
			}
		}
	}

	/**
	 * Used to implement the singleton format
	 */
	public static function getInstance() {
		if(self::$instance instanceof self) {
			return self::$instance;
		}
		self::$instance = new AkaiKiwi();
		return self::$instance;
	}

	private function baseRouter() {
		$path = $_SERVER['PHP_SELF'];
		if(substr($path, -1, 1) != '/') {
			$path .= '/';
		}

		$config = self::loadLib('Config');
		$basePath = $config->get_item('basePath');
		if(strpos($basePath, 'index.php') === FALSE) {
			$basePath .= '/index.php';
		}

		$query = explode($basePath, $path);
		$query = $query[1];
		$parts = explode('/', $query);
		array_shift($parts);
		$controller = empty($parts[0]) ? $config->get_item('defaultController') : $parts[0];
		$action = empty($parts[1]) ? $config->get_item('defaultAction') : $parts[1];

		// Parameters format example: key:value/value/value/
		for($i = 2; $i < count($parts) - 1; $i++) {
			if(strpos($parts[$i], ':') > 0) {
				$p = explode(':', $parts[$i]);
				$_GET[$p[0]] = $p[1];
			} else {
				$_GET[$parts[$i]] = null;
			}
		}

		$_GET['controller'] = $controller;
		$_GET['action'] = $action;
	}

	/**
	 * Gets the Loader object
	 */
	public static function getLoader() {
		return self::$loader;
	}

	/**
	 * Loads and returns a Library
	 * @param String $name
	 */
	public static function loadLib($name) {
		$r = NULL;
		if(strpos($name, ',') !== FALSE) {
			foreach(explode(',', $name) as $lib) {
				$r[] = self::$loader->loadLib(trim($lib));
			}
		} else {
			$r = self::$loader->loadLib($name);
		}
		return $r;
	}

	/**
	 * Loads a helper
	 * @param String $name The name of the helper, or many helpers comma-separated. Example: "urlhelper,formhelper"
	 */
	public static function loadHelper($name) {
		if(strpos($name, ',') !== FALSE) {
			foreach(explode(',', $name) as $helper) {
				self::$loader->loadHelper(trim($helper));
			}
		} else {
			self::$loader->loadHelper($name);
		}
	}
}
